/**
  * Author: Mei
  * Date: 2021-01-10 10:22
  * Description: 将各种可调用对象转换为function
  *
  */
#include "../head.h"

template<typename T>
struct function_traits;

//普通函数
template<typename Ret, typename ...Args>
struct function_traits<Ret(Args...)> {
public:
    enum {
        arity = sizeof...(Args)
    };

    typedef Ret function_type(Args...);

    typedef Ret return_type;
    using stl_function_type = function<function_type>;
    //using stl_function_type = function<Ret(Args...)>; //也可以这么指

    typedef Ret(*pointer)(Args...);

    template<size_t I>
    struct args {
        static_assert(I < arity, "index is out of range, index must less than sizeof Args");
        using type = typename tuple_element<I, tuple<Args...>>::type;
    };
};

//std::function
template<typename Ret, typename ...Args>
struct function_traits<function<Ret(Args...)>> : function_traits<Ret(Args...)> {
};

//member function
#define FUNCTION_TRAITS(...) \
template<typename ReturnType, typename ClassType, typename ...Args>\
struct function_traits<ReturnType(ClassType::*)(Args...) __VA_ARGS__>:\
function_traits<ReturnType(Args...)> {}; \

FUNCTION_TRAITS()
FUNCTION_TRAITS(const)
FUNCTION_TRAITS(volatile)
FUNCTION_TRAITS(const volatile)

//函数对象
template<typename Callable>
struct function_traits : function_traits<decltype(&Callable::operator())> {
};

template<typename Function>
typename function_traits<Function>::stl_function_type
to_function(const Function &lambda) {
    return static_cast<typename function_traits<Function>::stl_function_type>(lambda);
};

template<typename Function>
typename function_traits<Function>::stl_function_type
to_function(Function &&lambda) { //右值
    //cout << function_traits<Function>::arity << endl;
    return static_cast<typename function_traits<Function>::stl_function_type>(forward<Function>(lambda));
};

template<typename Function>
typename function_traits<Function>::pointer
to_function_pointer(const Function &lambda) {
    return static_cast<typename function_traits<Function>::pointer>(lambda);
};

int main1() {
    auto f = to_function([](int i, int j) { return i; });
    //auto f2 = to_function(2);

    function<int(int)> f1 = [](int i) { return i; };

    if (is_same<decltype(f), decltype(f1)>::value) {
        cout << "same" << endl;
    }

    return 0;
}